﻿using Microsoft.Extensions.Options;
using RabbitMQ.Client;
using System.Collections.Concurrent;

namespace Singer.Middleware.RabbitMQ;

/// <summary>
/// RabbitMQ连接池服务
/// </summary>
public class RabbitMQConnectionPool : IRabbitMQConnectionPool
{
    const string ConnectionNamePerfix = "singer_";
    RabbitMQOptions Options;
    ConcurrentDictionary<string, Lazy<IConnection>> Connections { get; }
    bool IsDisposed; // 是否已GC回收

    public RabbitMQConnectionPool(IOptions<RabbitMQOptions> options)
    {
        Options = options.Value;
        Connections = new ConcurrentDictionary<string, Lazy<IConnection>>();
    }

    /// <summary>
    /// 创建/获取 RabbitMQ连接
    /// </summary>
    /// <param name="connectionName">连接名</param>
    public IConnection Get(string? connectionName = null)
    {
        if (string.IsNullOrWhiteSpace(connectionName))
            connectionName = RabbitMQConnections.DefaultConnectionName;
        try
        {
            var lazyConnection = Connections.GetOrAdd(
                connectionName, (x) => new Lazy<IConnection>(() =>
                {
                    ConnectionFactory connectionFactory = Options.Connections.Get(connectionName);
                    return connectionFactory.CreateConnection($"{ConnectionNamePerfix}{connectionName}");
                })
            );
            return lazyConnection.Value;
        }
        catch (Exception ex)
        {
            Connections.TryRemove(connectionName, out _);
            throw new Exception($"【RabbitMQ】The '{connectionName}' connection failed. ErrorMessage：" + ex.Message);
        }
    }

    public void Dispose()
    {
        if (IsDisposed)
            return;
        foreach (var connection in Connections.Values)
        {
            try
            {
                connection.Value.Dispose();
            }
            catch (Exception)
            {
            }
        }
        Connections.Clear();
        IsDisposed = true;
    }
}
